package com.niiwoo.civet.mobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.mobile.vo.request.CreditCardAuthCallbackVO;
import com.niiwoo.civet.mobile.vo.request.TbAuthCallbackVO;
import com.niiwoo.civet.trade.dto.common.TcCreditAmountResultDTO;
import com.niiwoo.civet.trade.dto.request.AuditPointFackRequestDTO;
import com.niiwoo.civet.trade.dto.request.LoanAgainstFackRequestDTO;
import com.niiwoo.civet.trade.dto.request.RiskRuleRequestDTO;
import com.niiwoo.civet.trade.service.loan.SpeedLoanDubboService;
import com.niiwoo.civet.trade.service.loan.credit.CreditAmountDubboService;
import com.niiwoo.civet.user.dto.request.AFPCallbackDTO;
import com.niiwoo.civet.user.dto.request.DataStatusRequestDTO;
import com.niiwoo.civet.user.dto.request.SpeedLoanCreditCallbackDTO;
import com.niiwoo.civet.user.dto.response.DataStatusResponseDTO;
import com.niiwoo.civet.user.enums.SocialSecurityDataTypeEnum;
import com.niiwoo.civet.user.enums.UserDataStatusEnum;
import com.niiwoo.civet.user.enums.UserDataTypeEnum;
import com.niiwoo.civet.user.service.*;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.tiancheng.enums.AgainstFakeErrorCodeEnum;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.request.afp.AgainstFakeCallbackRequest;
import com.niiwoo.tripod.tiancheng.request.afp.CreditModelV2CallbackRequest;
import com.niiwoo.tripod.tiancheng.request.afp.RiskRuleCallbackRequest;
import com.niiwoo.tripod.tiancheng.request.auth.SocialDataCallbackRequest;
import com.niiwoo.tripod.tiancheng.request.auth.ThirdAuthCallbackRequest;
import com.niiwoo.tripod.tiancheng.request.common.AgainstFakeBaseRequest;
import com.niiwoo.tripod.tiancheng.response.afp.AuditPointFakeCallbackResponse;
import com.niiwoo.tripod.tiancheng.response.afp.LoanAgainstFakeCallbackResponse;
import com.niiwoo.tripod.tiancheng.response.afp.RiskRuleCallbackResponse;
import com.niiwoo.tripod.tiancheng.response.auth.ThirdAuthCallbackResponse;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeCallbackResponse;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeV2Response;
import com.niiwoo.tripod.tiancheng.response.common.CreditCallbackResponse;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.util.RequestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description: 天秤回调地址
 * @Author:LiJian
 * @Date:2017/11/10
 */
@Slf4j
@AuthIgnore
@RestController
@RequestMapping("/tc")
@Api(tags = "天秤回调", description = "/tc")
public class TianchengCallbackController {


    @Reference(version = "1.0.0")
    private UserStatusDubboService userStatusDubboService;

    @Reference(version = "1.0.0")
    private UserAuthZhiMaDubboService UserAuthZhiMaDubboService;

    @Reference(version = "1.0.0")
    private UserAuthSocialDubboService userAuthSocialDubboService;
    /**
     * 天秤成功的状态
     */
    private static final String TIANCHENG_SUCCESS_STATUS = "1";

    @Reference(version = "1.0.0")
    private UserCreditDubboService creditDubboService;

    @Reference(version = "1.0.0")
    private SpeedLoanDubboService speedLoanDubboService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Reference(version = "1.0.0")
    private UserAuthDubboService userAuthDubboService;

    @Reference(version = "1.0.0")
    private UserAuthCreditCardDubboService userAuthCreditCardDubboService;

    @Reference(version = "1.0.0")
    private CreditAmountDubboService creditAmountDubboService;

    @Reference(version = "1.0.0")
    private UserAuthJdDubboService userAuthJdDubboService;

    @Reference(version = "1.0.0")
    private UserAuthTbDubboService userAuthTbDubboService;

    /**
     * 授信反欺诈回调（RCE新模型，暂不做处理）
     */
    @ApiOperation("授信反欺诈回调（RCE新模型）")
    @RequestMapping(value = "/againstFakeV2/callback", produces = "text/plain;charset=utf-8")
    public String againstFakeV2Callback(@RequestBody AgainstFakeBaseRequest againstFakeBaseRequest) {
        AgainstFakeV2Response againstFakeV2Response = new AgainstFakeV2Response();
        againstFakeV2Response.setSession_id(againstFakeBaseRequest.getSession_id());
        againstFakeV2Response.setVersion(againstFakeBaseRequest.getVersion());
        againstFakeV2Response.setCode(AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode());
        againstFakeV2Response.setCode_desc("success");
        return JSON.toJSONString(againstFakeV2Response);
    }


    /**
     * 授信反欺诈回调（AFP老模型）`
     */
    @ApiOperation("授信反欺诈回调（AFP旧模型）")
    @RequestMapping(value = "/againstFake/callback", produces = "text/plain;charset=utf-8")
    public String againstFakeV2Callback(HttpServletRequest servletRequest) {
        String functionCode = servletRequest.getParameter("functionCode"); // URL中获取功能码
        log.info("授信反欺诈回调functionCode:{}, prams:{}", functionCode, JSON.toJSONString(servletRequest.getParameterMap()));
        if (StringUtils.isBlank(functionCode)) {
            throw new BizException("TC10001");
        }
        FunctionCodeEnum functionCodeEnum = FunctionCodeEnum.getByHeadFunctionCode(functionCode);
        if (functionCodeEnum == null) {
            throw new BizException("TC10002");
        }
        AgainstFakeCallbackRequest callbackResponse = new AgainstFakeCallbackRequest();
        String callbackData = servletRequest.getParameter("jsonString");
        if (StringUtils.isEmpty(callbackData)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("请求参数错误");
            return JSON.toJSONString(callbackResponse);
        }
        AgainstFakeCallbackResponse againstFakeResponse = JSON.parseObject(callbackData, AgainstFakeCallbackResponse.class);
        String uniqueId = againstFakeResponse.getUniqueID();
        if ((StringUtils.isEmpty(uniqueId))) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("UniqueID不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        String userId = againstFakeResponse.getUserId();
        if (StringUtils.isEmpty(userId)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("UserId不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        String modelResult = againstFakeResponse.getModelResult();
        if (StringUtils.isEmpty(modelResult)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("ModelResult不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        // 授信反欺诈业务处理
        AFPCallbackDTO afpCallbackDTO = new AFPCallbackDTO();
        afpCallbackDTO.setUserId(userId);
        afpCallbackDTO.setModelStatus(modelResult);
        afpCallbackDTO.setModelResult(againstFakeResponse.getMsgBody());
        switch (functionCodeEnum) {
            case LIBRA_FRAUD_CREDIT_OLD:
            case LIBRA_FRAUD_NO_ZHIMA_CREDIT_OLD:
                RpcContext.getContext().asyncCall(() -> creditDubboService.speedLoanCreditAgainstFakeHandle(afpCallbackDTO));
//                creditDubboService.speedLoanCreditAgainstFakeHandle(afpCallbackDTO);
                break;
            default:
                break;
        }
        callbackResponse.setResult("1");
        callbackResponse.setMessage("成功");
        callbackResponse.setTotalCount(0);
        AgainstFakeCallbackRequest.DataInfo dataInfo = new AgainstFakeCallbackRequest.DataInfo();
        dataInfo.setUniqueID(uniqueId);
        callbackResponse.setData(dataInfo);
        return JSON.toJSONString(callbackResponse);

    }


    @ApiOperation("授权成功回调：当天秤H5授权完成以后，会通过此地址给商家发送http的post请求来通知数据状态")
    @RequestMapping(value = "/authOperatorNotify/callback", produces = "text/plain;charset=utf-8")
    public String authOperatorNotify(HttpServletRequest request) {

        //参数判断处理及解密
        ThirdAuthCallbackRequest callbackRequest = null;
        JSONObject jsonObject = RequestUtil.traceRequest(request);
        JSONObject paramsJsonObject = jsonObject.getJSONObject("params");
        String jsonString = paramsJsonObject.toJSONString();
        log.info("OperatorNotify运营商授权回调后参数：" + jsonString);
        try {
            JSONObject busiData = userAuthDubboService.resolveEncryptCallbackData(jsonString);
            log.info("运营商授权回调解密后参数：" + busiData.toJSONString());
            callbackRequest = JSONObject.parseObject(busiData.toJSONString(), ThirdAuthCallbackRequest.class);
        } catch (IOException e) {
            log.info("运营商授权回调数据解析错误");
            return ThirdAuthCallbackResponse.fail("解析错误");
        }
        if (callbackRequest == null) {
            log.info("运营商授权回调参数为空");
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        log.info("运营商授权回调userId={},请求参数={}", callbackRequest.getUserId(), callbackRequest);
        if (StringUtils.isBlank(callbackRequest.getUserId())
                || StringUtils.isBlank(callbackRequest.getStatus())
                || StringUtils.isBlank(callbackRequest.getAuthorizeType())) {
            log.info("运营商授权回调参数为空", callbackRequest);
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        UserDataTypeEnum dataTypeEnum = matchType(callbackRequest.getAuthorizeType());
        if (!UserDataTypeEnum.OPERATOR_AUTHORIZE.equals(dataTypeEnum)) {
            return ThirdAuthCallbackResponse.fail("回调类型不是运营商类型");
        }
        log.debug("授权成功回调：" + JSON.toJSONString(callbackRequest));

        //判断回调状态
        String userId = callbackRequest.getUserId();
        DataStatusRequestDTO dataStatusRequestDTO = new DataStatusRequestDTO();
        dataStatusRequestDTO.setDataType(UserDataTypeEnum.OPERATOR_AUTHORIZE.getValue());
        dataStatusRequestDTO.setUserId(userId);
        Byte status = null;
        if (TIANCHENG_SUCCESS_STATUS.equals(callbackRequest.getStatus())) {
            status = UserDataStatusEnum.PhoneOperatorStatus.ALREADY_CREDIT.getStatus();
            dataStatusRequestDTO.setAuthTime(new Date());
        } else {
            status = UserDataStatusEnum.PhoneOperatorStatus.NOCREDIT.getStatus();
        }

        //判断如果已数据回调成功就直接返回
        DataStatusResponseDTO existsData = userStatusDubboService.getByUserIdAndType(userId, UserDataTypeEnum.OPERATOR_AUTHORIZE);
        if(existsData != null){
            if(UserDataStatusEnum.PhoneOperatorStatus.ALREADY_CREDIT.getStatus().equals(existsData.getDataStatus())){
                return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
            }
        }

        //修改修改用户数据状态及返回结果
        dataStatusRequestDTO.setDataStatus(status);
        int result = userStatusDubboService.saveDataStatusByUserIdAndType(dataStatusRequestDTO);
        if (result > 0) {
            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        }
        return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
    }

    @ApiOperation("运营商数据回调：当天秤H5授权完成并获取到用户数据以后，会通过此地址给商家发送http的post请求来通知数据状态")
    @RequestMapping(value = "/authOperatorCallback/callback", produces = "text/plain;charset=utf-8")
    public String authOperatorCallback(ThirdAuthCallbackRequest callbackRequest) {

        log.info("authOperatorCallback运营商数据回调参数：" + callbackRequest);
        //回调参数判断及解析
        if (callbackRequest == null) {
            log.info("authOperatorCallback运营商数据回调参数为空");
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        log.info("运营商数据回调userId={},请求参数={}", callbackRequest.getUserId(), callbackRequest);
        String userId = callbackRequest.getUserId();
        Byte status = mappingOperatorDataStatus(callbackRequest.getStatus());
        if (status == null) {
            return null;
        }

        //修改用户授权数据状态
        DataStatusRequestDTO dataStatusRequestDTO = new DataStatusRequestDTO();
        dataStatusRequestDTO.setDataType(UserDataTypeEnum.OPERATOR_AUTHORIZE.getValue());
        dataStatusRequestDTO.setUserId(userId);
        dataStatusRequestDTO.setDataStatus(status);
        int result = userStatusDubboService.saveDataStatusByUserIdAndType(dataStatusRequestDTO);
        if (result > 0) {
            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        }
        return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
    }

    /**
     * 运营商授权状态映射：天秤回调的状态参数与本项目定义的状态关系映射
     *
     * @param status
     * @return java.lang.Byte
     * @author zzl
     * @date 2017/12/1 21:56
     */
    private Byte mappingOperatorDataStatus(String status) {
        /*
        天秤运营商数据回调的状态：
         status 字段：值范围为（1,2,3,4），具体返回参考以下说明
        a) 当该接口未传入 concernData 时，授权成功之后告知数据获取状态， 执行一次回调。
        返回 1 表示未获取到有效通话详单数据，返回 2 表示有获取到有效通话详单数据。
        b) 当该接口传入了 concernData 时，授权成功之后告知数据爬取状态， 执行两次回调。
        第 1 次回调，是在用户 concernData 字段指定数据获取完调用，返回 3 表示未获取
        到有效指定数据，返回 4 表示有获取到有效指定数据；第 2 次回调，是在用户所有
        数据获取完调用，返回 1 表示未获取到有效通话详单数据，返回 2 表示有获取到有
        效通话详单数据。
       */

        /*
        本项目定义的状态：
        NOCREDIT((byte) 0, "未授权"),
        ALREADY_CREDIT((byte) 1, "已授权"),
        GETSUCCESS((byte) 2, "已验证（获取数据）"),
        GETFAIL((byte) 3, "验证失败（获取数据失败）"),
        EXPIRED((byte) 4, "已过期");
         */
        switch (status) {
            case "4":
                return UserDataStatusEnum.PhoneOperatorStatus.GETSUCCESS.getStatus();
            case "2":
                return UserDataStatusEnum.PhoneOperatorStatus.GETSUCCESS.getStatus();
            default:
                return UserDataStatusEnum.PhoneOperatorStatus.GETFAIL.getStatus();
        }

    }

    /**
     * 社保状态映射：天秤回调的状态与本项目定义的状态的对应关系参数处理
     *
     * @param
     * @return
     * @author zzl
     * @date 2017/12/1 21:55
     */
    private Byte mappingSocialSecurityDataStatus(String status) {
        /*
        天秤回调状态status说明：
        100：获取失败
        200：获取成功且身份一致
        300：获取成功且身份不一致

       */

        /*
        本项目社保相关状态UserDataStatusEnum.SocialSecurityStatus ：
        NOCREDIT((byte) 0, "未授权"),
        ALREADY_CREDIT((byte) 1, "已授权"),
        GETSUCCESS((byte) 2, "已验证（获取数据）"),
        GETFAIL((byte) 3, "验证失败（获取数据失败）"),
        EXPIRED((byte) 4, "已过期");
         */
        log.info("天秤社保数据回调状态");
        switch (status) {
            case "200":
                return UserDataStatusEnum.SocialSecurityStatus.GETSUCCESS.getStatus();
            case "100":
                return UserDataStatusEnum.SocialSecurityStatus.GETFAIL.getStatus();
            case "300":
                return UserDataStatusEnum.SocialSecurityStatus.DIFFER.getStatus();
            case "0":
                return null;
            default:
                return null;
        }

    }

    /**
     * 天秤授信（AFP老模型）
     */
    @ApiOperation("天秤授信回调（AFP旧模型）")
    @RequestMapping(value = "/credit/callback", produces = "text/plain;charset=utf-8")
    public String creditCallback(HttpServletRequest servletRequest) {
        String functionCode = servletRequest.getParameter("functionCode"); // URL中获取功能码
        log.info("天秤授信回调functionCode:{}, prams:{}", functionCode, JSON.toJSONString(servletRequest.getParameterMap()));
        if (StringUtils.isBlank(functionCode)) {
            throw new BizException("TC10001");
        }
        FunctionCodeEnum functionCodeEnum = FunctionCodeEnum.getByHeadFunctionCode(functionCode);
        if (functionCodeEnum == null) {
            throw new BizException("TC10002");
        }
        AgainstFakeCallbackRequest callbackResponse = new AgainstFakeCallbackRequest();
        String callbackData = servletRequest.getParameter("jsonString");
        if (StringUtils.isEmpty(callbackData)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("请求参数错误");
            return JSON.toJSONString(callbackResponse);
        }
        CreditCallbackResponse creditCallbackResponse = JSON.parseObject(callbackData, CreditCallbackResponse.class);
        String uniqueId = creditCallbackResponse.getUniqueID();
        if ((StringUtils.isEmpty(uniqueId))) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("UniqueID不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        String userId = creditCallbackResponse.getUserId();
        if (StringUtils.isEmpty(userId)) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("UserId不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        Integer fastBorrowType = creditCallbackResponse.getFastBorrowType();
        if (fastBorrowType == null) {
            callbackResponse.setResult("-1");
            callbackResponse.setMessage("FastBorrowType不能为空");
            return JSON.toJSONString(callbackResponse);
        }
        Integer isMultipleModel = creditCallbackResponse.getIsMultipleModel();
        switch (functionCodeEnum) {
            case SPEED_LOAN_CREDIT_DATA_FLOW:
                if (isMultipleModel != null && isMultipleModel == 1) {
                    callbackResponse.setResult("-1");
                    callbackResponse.setMessage("IsMultipleModel与模型不匹配");
                    return JSON.toJSONString(callbackResponse);
                }
                if (creditCallbackResponse.getFastBorrowType() == null) {
                    callbackResponse.setResult("-1");
                    callbackResponse.setMessage("FastBorrowType不能为空");
                    return JSON.toJSONString(callbackResponse);
                }
                SpeedLoanCreditCallbackDTO speedLoanCreditCallback = new SpeedLoanCreditCallbackDTO();
                speedLoanCreditCallback.setUserId(userId);
                speedLoanCreditCallback.setCreditAmount(creditCallbackResponse.getCreditAmount());
                speedLoanCreditCallback.setFastBorrowType(creditCallbackResponse.getFastBorrowType());
                speedLoanCreditCallback.setMsgBody(creditCallbackResponse.getMsgBody());
                RpcContext.getContext().asyncCall(() -> creditDubboService.speedLoanCreditHandle(speedLoanCreditCallback));
//                creditDubboService.speedLoanCreditHandle(speedLoanCreditCallback);
                break;
            default:
                break;
        }
        callbackResponse.setResult("1");
        callbackResponse.setMessage("成功");
        callbackResponse.setTotalCount(0);
        AgainstFakeCallbackRequest.DataInfo dataInfo = new AgainstFakeCallbackRequest.DataInfo();
        dataInfo.setUniqueID(uniqueId);
        callbackResponse.setData(dataInfo);
        return JSON.toJSONString(callbackResponse);

    }

    /**
     * 借款反欺诈回调
     */
    @ApiOperation("借款反欺诈回调")
    @RequestMapping(value = "/loanFake/{projectId}/callback", produces="text/plain;charset=utf-8")
    public String loanFakeCallback(@PathVariable(name = "projectId") Long projectId,HttpServletRequest servletRequest) {
        try {
            String jsonString = servletRequest.getParameter("jsonString");
            log.info("借款反欺诈回调,标的ID={},请求参数={}.", projectId, jsonString);
            if (StringUtils.isEmpty(jsonString)) {
                log.error("借款反欺诈回调,标的ID={},发生异常,原因是请求参数为空.", projectId);
                return JSON.toJSONString(new AgainstFakeCallbackRequest(AgainstFakeCallbackRequest.FAIL, "请求参数为空."));
            }

            LoanAgainstFakeCallbackResponse loanAgainstFakeCallbackResponse = JSON.parseObject(jsonString, LoanAgainstFakeCallbackResponse.class);
            log.info("借款反欺诈回调,标的ID={},请求参数转换后={}.", projectId, JSON.toJSONString(loanAgainstFakeCallbackResponse));
            AgainstFakeCallbackRequest againstFakeCallbackRequest = checkLoanFakeCallbackParam(loanAgainstFakeCallbackResponse);
            if (againstFakeCallbackRequest.isSuccess()) {
                LoanAgainstFackRequestDTO loanAgainstFackRequestDTO = new LoanAgainstFackRequestDTO();
                loanAgainstFackRequestDTO.setModelResult(loanAgainstFakeCallbackResponse.getModelResult());
                loanAgainstFackRequestDTO.setPlatformType(loanAgainstFakeCallbackResponse.getPlatform_type());
                loanAgainstFackRequestDTO.setProjectId(projectId);
                speedLoanDubboService.loanAgainstFakeCallback(loanAgainstFackRequestDTO);

                return JSON.toJSONString(AgainstFakeCallbackRequest.getSuccessInstance());
            } else {
                log.error("借款反欺诈回调,标的ID={},发生异常,原因={}.", againstFakeCallbackRequest);
                return JSON.toJSONString(againstFakeCallbackRequest);
            }
        }catch(Exception e){
            log.error("借款反欺诈回调,标的ID={},发生系统异常,原因={}.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 风险规则回调
     */
    @ApiOperation("风险规则回调")
    @RequestMapping(value = "/riskRule/{projectId}/callback", produces="text/plain;charset=utf-8")
    public String riskRuleCallback(@RequestBody JSONObject param,@PathVariable(name = "projectId") Long projectId,HttpServletRequest servletRequest) {
        log.info("风险规则回调,标的ID={},请求参数={}",projectId,param.toJSONString());

        if(param==null) {
            log.error("风险规则回调,标的ID={},发生异常,原因是请求参数为空.",projectId);
            return JSON.toJSONString(new RiskRuleCallbackRequest(RiskRuleCallbackRequest.FAIL,"请求参数为空."));
        }
        RiskRuleCallbackResponse riskRuleCallbackResponse = JSON.toJavaObject(param, RiskRuleCallbackResponse.class);
        riskRuleCallbackResponse.setProjectId(projectId);
        RiskRuleCallbackRequest riskRuleCallbackRequest=checkRiskRuleCallbackParam(riskRuleCallbackResponse);
        if(riskRuleCallbackRequest.isSuccess()){
            speedLoanDubboService.riskRuleCallback(transRiskRuleCallbackResponse2RiskRuleRequestDTO(riskRuleCallbackResponse));
        }else{
            log.error("风险规则回调,标的ID={},发生异常,原因={}",projectId,riskRuleCallbackRequest);
            JSON.toJSONString(riskRuleCallbackRequest);
        }

        return JSON.toJSONString(RiskRuleCallbackRequest.getSuccessInstance());
    }

    /**
     * 转换风险回调参数
     * @param riskRuleCallbackResponse
     * @return
     */
    private RiskRuleRequestDTO transRiskRuleCallbackResponse2RiskRuleRequestDTO(RiskRuleCallbackResponse riskRuleCallbackResponse){
        RiskRuleRequestDTO riskRuleRequestDTO=new RiskRuleRequestDTO();
        riskRuleRequestDTO.setStatus(riskRuleCallbackResponse.getStatus());
        riskRuleRequestDTO.setProjectId(riskRuleCallbackResponse.getProjectId());
        riskRuleRequestDTO.setMessage(riskRuleCallbackResponse.getMessage());
        riskRuleRequestDTO.setUserId(riskRuleCallbackResponse.getUserId());
        riskRuleRequestDTO.setFromSource(riskRuleCallbackResponse.getFromSource());

        List<RiskRuleRequestDTO.VarResult> varResultList4RiskRuleRequest=new ArrayList<RiskRuleRequestDTO.VarResult>();
        for(RiskRuleCallbackResponse.VarResult varResult:riskRuleCallbackResponse.getVarsResult()){
            RiskRuleRequestDTO.VarResult varResult4RiskRuleRequest=riskRuleRequestDTO.new VarResult();
            varResult4RiskRuleRequest.setCode(varResult.getCode());
            varResult4RiskRuleRequest.setCodeDesc(varResult.getCodeDesc());
            varResult4RiskRuleRequest.setComputeEndTime(varResult.getComputeEndTime());
            varResult4RiskRuleRequest.setComputeStartTime(varResult.getComputeStartTime());
            varResult4RiskRuleRequest.setDetailJson(varResult.getDetailJson());
            varResult4RiskRuleRequest.setVarId(varResult.getVarId());
            varResult4RiskRuleRequest.setVarValue(varResult.getVarValue());
            varResult4RiskRuleRequest.setVarNameCn(varResult.getVarNameCn());
            varResult4RiskRuleRequest.setVarNameEn(varResult.getVarNameEn());
            varResult4RiskRuleRequest.setVarQueryType(varResult.getVarQueryType());

            varResultList4RiskRuleRequest.add(varResult4RiskRuleRequest);
        }
        riskRuleRequestDTO.setVarsResult(varResultList4RiskRuleRequest);

        return riskRuleRequestDTO;
    }

    /**
     * 审核要点反欺诈回调
     */
    @ApiOperation("审核要点反欺诈回调")
    @RequestMapping(value = "/auditPointFake/{projectId}/callback", produces="text/plain;charset=utf-8")
    public String auditFakeCallback(@PathVariable(name = "projectId") Long projectId,HttpServletRequest servletRequest) {
        String jsonString = servletRequest.getParameter("jsonString");
        log.info("天称审核要点反欺诈回调,标的ID={},请求参数={}",projectId,jsonString);
        if(StringUtils.isEmpty(jsonString)) {
            return JSON.toJSONString(new AgainstFakeCallbackRequest(AgainstFakeCallbackRequest.FAIL,"请求参数为空."));
        }

        AuditPointFakeCallbackResponse auditPointFakeCallbackResponse = JSON.parseObject(jsonString, AuditPointFakeCallbackResponse.class);
        AgainstFakeCallbackRequest againstFakeCallbackRequest=checkAuditPointFakeCallbackParam(auditPointFakeCallbackResponse);
        if(againstFakeCallbackRequest.isSuccess()){
            AuditPointFackRequestDTO auditPointFackRequestDTO=new AuditPointFackRequestDTO();
            auditPointFackRequestDTO.setProjectId(Long.valueOf(auditPointFakeCallbackResponse.getMsgBody().getProjectId()));
            auditPointFackRequestDTO.setAuditPoints(auditPointFakeCallbackResponse.getMsgBody().getAudit_points());
            auditPointFackRequestDTO.setAuditResult(auditPointFakeCallbackResponse.getMsgBody().getAudit_result());
            auditPointFackRequestDTO.setStatus(auditPointFakeCallbackResponse.getStatus());

            speedLoanDubboService.auditPointFakeCallback(auditPointFackRequestDTO);

            return JSON.toJSONString(AgainstFakeCallbackRequest.getSuccessInstance());
        }else{
            log.error("天称审核要点反欺诈回调,标的ID={},发生异常,原因={}",projectId,againstFakeCallbackRequest);
            return JSON.toJSONString(againstFakeCallbackRequest);
        }
    }

    private AgainstFakeCallbackRequest checkLoanFakeCallbackParam(LoanAgainstFakeCallbackResponse loanAgainstFakeCallbackResponse){
        if(loanAgainstFakeCallbackResponse==null){
            return new AgainstFakeCallbackRequest(AgainstFakeCallbackRequest.FAIL,"请求参数为空.");
        }

        String uniqueId = loanAgainstFakeCallbackResponse.getUniqueID();
        if((StringUtils.isEmpty(uniqueId))) {
            return new AgainstFakeCallbackRequest(AgainstFakeCallbackRequest.FAIL,"UniqueID不能为空");
        }

        String modelResult = loanAgainstFakeCallbackResponse.getModelResult();
        if(StringUtils.isEmpty(modelResult)) {
            return new AgainstFakeCallbackRequest(AgainstFakeCallbackRequest.FAIL,"ModelResult不能为空");
        }

        return AgainstFakeCallbackRequest.getSuccessInstance();
    }

    private RiskRuleCallbackRequest checkRiskRuleCallbackParam(RiskRuleCallbackResponse riskRuleCallbackResponse){
        if(riskRuleCallbackResponse.getStatus()==null) {
            log.error("风险规则回调,标的ID={},发生异常,原因是status为空.",riskRuleCallbackResponse.getProjectId());
            return new RiskRuleCallbackRequest(RiskRuleCallbackRequest.FAIL,"status不能为空");
        }

        if(riskRuleCallbackResponse.getVarsResult()==null||riskRuleCallbackResponse.getVarsResult().size()==0) {
            log.error("风险规则回调,标的ID={},发生异常,原因是varsResult为空.",riskRuleCallbackResponse.getProjectId());
            return new RiskRuleCallbackRequest(RiskRuleCallbackRequest.FAIL,"varsResult不能为空");
        }

        return RiskRuleCallbackRequest.getSuccessInstance();
    }

    private AgainstFakeCallbackRequest checkAuditPointFakeCallbackParam(AuditPointFakeCallbackResponse auditPointFakeCallbackResponse){
        if((StringUtils.isEmpty(auditPointFakeCallbackResponse.getStatus()))) {
            return AgainstFakeCallbackRequest.getFailInstance("Status不能为空");
        }

        if(auditPointFakeCallbackResponse.getMsgBody()==null) {
            return AgainstFakeCallbackRequest.getFailInstance("MsgBody不能为空");
        }

        return AgainstFakeCallbackRequest.getSuccessInstance();
    }

    @ApiOperation("社保授权成功回调：当天秤H5授权完成以后，会通过此地址给商家发送http的post请求来通知数据状态")
    @RequestMapping(value = "/authSocialSecurityNotify/callback", produces = "text/plain;charset=utf-8")
    public String authSocialSecurityNotify(HttpServletRequest request) {

        //参数解析，解密及判断
        ThirdAuthCallbackRequest callbackRequest = null;
        JSONObject jsonObject = RequestUtil.traceRequest(request);
        JSONObject paramsJsonObject = jsonObject.getJSONObject("params");
        String paramsString = paramsJsonObject.toJSONString();
        log.info("SocialSecurityNotify社保授权回调参数：" + paramsString);
        try {
            JSONObject busiData = userAuthDubboService.resolveEncryptCallbackData(paramsString);
            log.info("社保授权回调解密后参数：" + busiData.toJSONString());
            callbackRequest = JSONObject.parseObject(busiData.toJSONString(), ThirdAuthCallbackRequest.class);
        } catch (IOException e) {
            log.info("社保授权回调数据解析错误");
            return ThirdAuthCallbackResponse.fail("解析错误");
        }
        if (callbackRequest == null) {
            log.info("社保授权回调参数为空");
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        log.info("社保授权回调userId={},请求参数={}", callbackRequest.getUserId(), callbackRequest);
        if (StringUtils.isBlank(callbackRequest.getUserId())
                || StringUtils.isBlank(callbackRequest.getStatus())
                || StringUtils.isBlank(callbackRequest.getAuthorizeType())) {
            log.info("社保授权回调参数为空", callbackRequest);
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        UserDataTypeEnum dataTypeEnum = matchType(callbackRequest.getAuthorizeType());
        if (!UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE.equals(dataTypeEnum)) {
            return ThirdAuthCallbackResponse.fail("回调类型不是社保类型");
        }

        //解析业务参数
        String userId = callbackRequest.getUserId();

        //判断已数据回调成功，就直接返回成功
        DataStatusResponseDTO existsData = userStatusDubboService.getByUserIdAndType(userId, UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE);
        if(existsData != null){
            if(UserDataStatusEnum.SocialSecurityStatus.ALREADY_CREDIT.getStatus().equals(existsData.getDataStatus())){
                return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
            }
        }

        UserDataStatusEnum.SocialSecurityStatus status = null;
        String city = null;
        Date authTime = null;
        if (TIANCHENG_SUCCESS_STATUS.equals(callbackRequest.getStatus())) {
            //授权成功
            status = UserDataStatusEnum.SocialSecurityStatus.ALREADY_CREDIT;
            authTime = new Date();
            try {
                //成功还要解析城市信息
                String userInfo = StringUtils.replace(callbackRequest.getUserInfo(), "\\", "");
                //如果有双引号,去除首尾双引号
                if(userInfo.charAt(0) == '\"' && userInfo.charAt(userInfo.length()-1) == '\"') {
                    userInfo = StringUtils.substring(userInfo, 1, userInfo.length() - 1);
                }
                JSONObject userInfoJsonObject = JSON.parseObject(userInfo);
                city = userInfoJsonObject.getString("city");
            }catch (Exception e){
                log.error("社保授权回调解析用户信息失败", e);
            }
        } else {
            //授权失败
            status = UserDataStatusEnum.SocialSecurityStatus.NOCREDIT;
        }

        //保存用户授权数据状态
        try {
            userAuthSocialDubboService.saveUserSocialInfo(userId, city, status, authTime);
            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
        }
    }

    @ApiOperation("社保数据回调：当天秤H5授权完成并获取到用户数据以后，会通过此地址给商家发送http的post请求来通知数据状态")
    @RequestMapping(value = "/authSocialSecurityCallback/callback/{userId}", produces = "text/plain;charset=utf-8")
    public String authSocialSecurityCallback(HttpServletRequest servletRequest, @PathVariable("userId") String userId) {
        String jsonString = servletRequest.getParameter("jsonString");
        if (StringUtils.isEmpty(jsonString)) {
            return ThirdAuthCallbackResponse.fail("请求参数为空");
        }
        log.info("社保数据回调参数json:" + jsonString);
        SocialDataCallbackRequest callbackRequest = JSON.parseObject(jsonString, SocialDataCallbackRequest.class);
        if (callbackRequest == null) {
            log.info("社保数据回调参数为空");
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        log.info("社保数据回调userId={},请求参数={}", userId, callbackRequest);
        if (StringUtils.isBlank(userId)|| StringUtils.isBlank(callbackRequest.getStatus())) {
            log.info("天秤社保数据回调参数为空{}", callbackRequest);
            return ThirdAuthCallbackResponse.fail("参数不正确");
        }
        Byte status = mappingSocialSecurityDataStatus(callbackRequest.getStatus());
        if (status == null) {
            //否则不需要更新状态，return 0
            return JSON.toJSONString(ThirdAuthCallbackResponse.success("不需要更新状态"));
        }

        if (status == 0) {
            return JSON.toJSONString(ThirdAuthCallbackResponse.success("不需要更新状态"));
        }
        DataStatusRequestDTO dataStatusResponseDTO = new DataStatusRequestDTO();
        dataStatusResponseDTO.setDataType(UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE.getValue());
        dataStatusResponseDTO.setUserId(userId);
        dataStatusResponseDTO.setDataStatus(status);
        dataStatusResponseDTO.setAuthTime(new Date());

        int result = userStatusDubboService.saveDataStatusByUserIdAndType(dataStatusResponseDTO);

        try {
            //异步调用查询天秤社保数据，并保存到snapdata
            RpcContext.getContext().asyncCall(() -> userAuthSocialDubboService.saveSocialSecurity(userId, null, SocialSecurityDataTypeEnum.SELF_TYPE));
        } catch (Exception e) {
            log.error("调用查询并保存天秤的社保数据失败" + e.getMessage(), e);
            return ThirdAuthCallbackResponse.fail("调用查询并保存天秤的社保数据失败");
        }
        if (result > 0) {

            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        }

        return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
    }

    /**
     * 匹配授权回调时的类型（非数据回调）
     *
     * @param authorizeType
     * @return
     */
    private UserDataTypeEnum matchType(String authorizeType) {
        /*
        天秤的定义：
        1.运营商授权
        2.社保授权
        3.人行征信授权
        4.芝麻分授权
         */
        switch (authorizeType) {
            case "1":
                return UserDataTypeEnum.OPERATOR_AUTHORIZE;
            case "2":
                return UserDataTypeEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE;
            case "4":
                return UserDataTypeEnum.ZHIMA_AUTHORIZE;
            default:
                return null;
        }
    }

    @ApiOperation("芝麻授权回调")
    @RequestMapping(value = "/authZhiMaNotify/callback", produces = "text/plain;charset=utf-8")
    public String authZhiMaNotify(ThirdAuthCallbackRequest callbackRequest) {
        if (callbackRequest == null) {
            log.info("芝麻授权参数为空");
            return ThirdAuthCallbackResponse.fail("参数为空");
        }
        log.info("芝麻授权回调userId={},请求参数={}", callbackRequest.getUserId(), callbackRequest);
        UserDataTypeEnum dataTypeEnum = matchType(callbackRequest.getAuthorizeType());
        if (!UserDataTypeEnum.ZHIMA_AUTHORIZE.equals(dataTypeEnum)) {
            return ThirdAuthCallbackResponse.fail("回调类型不是芝麻类型");
        }
        String userId = callbackRequest.getUserId();
        DataStatusRequestDTO dataStatusRequestDTO = new DataStatusRequestDTO();
        dataStatusRequestDTO.setDataType(UserDataTypeEnum.ZHIMA_AUTHORIZE.getValue());
        dataStatusRequestDTO.setUserId(userId);
        UserDataStatusEnum.ZhimaCreditStatus status = null;
        Date authTime = null;
        if (TIANCHENG_SUCCESS_STATUS.equals(callbackRequest.getStatus())) {
            status = UserDataStatusEnum.ZhimaCreditStatus.PASS_APPLY;
            authTime = new Date();
        } else {
            //授权失败
            status = UserDataStatusEnum.ZhimaCreditStatus.FAIL_APPLY;
        }

        //原因字段最大长度50的处理
        String failureReason = callbackRequest.getMsg();
        if (StringUtils.isNotBlank(failureReason)) {
            if (failureReason.length() > 50) {
                failureReason = failureReason.substring(0, 50);
            }
        }

        UserAuthZhiMaDubboService.updateZhiMaScore(userId, failureReason, status, authTime);
        return ThirdAuthCallbackResponse.success("用户状态数据更新成功");

    }


    @ApiOperation("信用卡授权成功回调：当天秤H5授权完成以后，会通过此地址给商家发送http的post请求来通知数据状态")
    @RequestMapping(value = "/authCreditCardData/callback", produces = "text/plain;charset=utf-8")
    public String authCreditCardDataCallback(CreditCardAuthCallbackVO creditCardAuthCallbackVO) {
        String jsonString = JSON.toJSONString(creditCardAuthCallbackVO);
        log.info("信用卡数据回调参数:" + jsonString);

        //参数判断处理及解密
        boolean result = userAuthCreditCardDubboService.dataCallBack(jsonString);

        if (result) {
            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        }
        return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
    }


    /**
     * 天秤模型计算回调（RCE新模型）
     * @param servletRequest
     * @param eventType     参考TianchengCallbackEventEnum
     * @param projectId
     * @param projectType   参考ProjectTypeEnum
     * @param againstFakeBaseRequest
     * @return
     */
    @ApiOperation("天秤模型计算回调（RCE新模型）")
    @RequestMapping(value = "/v2/{eventType}/{projectId}/{projectType}/callback", produces = "text/plain;charset=utf-8")
    public String modelCalculationCallback(HttpServletRequest servletRequest,
                                           @PathVariable("eventType") String eventType,
                                           @PathVariable("projectId") Long projectId,
                                           @PathVariable("projectType") String projectType,
                                           @RequestBody AgainstFakeBaseRequest againstFakeBaseRequest){

        String functionCode = servletRequest.getParameter("functionCode");      // URL中获取功能码
        log.info("天秤模型计算回调:functionCode={}, requestPrams={}", functionCode, JSON.toJSONString(againstFakeBaseRequest));
        if (StringUtils.isBlank(functionCode)) {
            throw new BizException("TC10001");
        }
        FunctionCodeEnum functionCodeEnum = FunctionCodeEnum.getByHeadFunctionCode(functionCode);
        if (functionCodeEnum == null) {
            throw new BizException("TC10002");
        }
        log.info("RCE新模型function{}",JSONObject.toJSONString(functionCodeEnum));

        try {
            String msgBody = JSON.toJSONString(againstFakeBaseRequest.getMsg_body());
            JSONObject msgBodyJSON = JSONObject.parseObject(msgBody);
            CreditModelV2CallbackRequest creditModelV2CallbackRequest = msgBodyJSON.toJavaObject(CreditModelV2CallbackRequest.class);

            //授信（额度评分卡）
            if (functionCodeEnum == FunctionCodeEnum.LIBRA_CREDIT_CARD_LOAN_TWO ||
                    functionCodeEnum == FunctionCodeEnum.LIBRA_SOCIAL_SECURITY_LOAN ||
                    functionCodeEnum == FunctionCodeEnum.LIBRA_MICROFINANCE_LOAN ||
                    functionCodeEnum == FunctionCodeEnum.LIBRA_SOCIAL_SECURITY_TE_LOAN ||
                    functionCodeEnum == FunctionCodeEnum.LIBRA_CREDIT_CARD_TE_LOAN ||
                    functionCodeEnum == FunctionCodeEnum.LIBRA_CONSUME_LOAN){
                TcCreditAmountResultDTO amountResultDTO = new TcCreditAmountResultDTO();
                amountResultDTO.setReserve(againstFakeBaseRequest.getReserve());
                amountResultDTO.setStatus(creditModelV2CallbackRequest.getStatus());
                amountResultDTO.setMessage(creditModelV2CallbackRequest.getMessage());
                amountResultDTO.setCreditAmount(creditModelV2CallbackRequest.getStatus() == AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode() ? creditModelV2CallbackRequest.getResult().getCredit_amount() : null);
                RpcContext.getContext().asyncCall(() -> creditAmountDubboService.scoreCardTcCallback(functionCode, amountResultDTO));
            }
        } catch (Exception e) {
            log.error("【天秤模型计算回调（RCE新模型）异常】functionCode={}, requestPrams={}", functionCode, JSON.toJSONString(againstFakeBaseRequest), e);
            throw new BizException("TC10005");
        }

        AgainstFakeV2Response againstFakeV2Response = new AgainstFakeV2Response();
        againstFakeV2Response.setSession_id(againstFakeBaseRequest.getSession_id());
        againstFakeV2Response.setVersion(againstFakeBaseRequest.getVersion());
        againstFakeV2Response.setCode(AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode());
        againstFakeV2Response.setCode_desc("success");
        return JSON.toJSONString(againstFakeV2Response);
    }

    @ApiOperation("京东数据成功回调：当天秤H5授权完成以后，会通过此地址给商家发送http的post请求来通知数据状态[张子龙]v5.1.5")
    @RequestMapping(value = "/authJdData/callback", produces = "text/plain;charset=utf-8")
    public String authJdDataCallback(CreditCardAuthCallbackVO creditCardAuthCallbackVO, HttpServletRequest request) {
        String jsonString = JSON.toJSONString(creditCardAuthCallbackVO);
        log.info("京东数据回调参数:" + jsonString);
        log.info("jd数据回调参数:"+ JSON.toJSONString(request.getParameterMap()));

        //参数判断处理及解密
        boolean result = userAuthJdDubboService.dataCallBack(jsonString);

        if (result) {
            return ThirdAuthCallbackResponse.success("用户状态数据更新成功");
        }
        return ThirdAuthCallbackResponse.fail("用户状态数据更新失败");
    }

    @ApiOperation("淘宝数据成功回调：当天秤抓取数据完成后，会通过此地址通知.[张子龙]v5.5.8")
    @RequestMapping(value = "/authTbData/callback", produces = "text/plain;charset=utf-8")
    public String authTbDataCallback(TbAuthCallbackVO tbAuthCallbackVO, HttpServletRequest request) {
        if(tbAuthCallbackVO == null || StringUtils.isBlank(tbAuthCallbackVO.getBusiData())){
            return ThirdAuthCallbackResponse.fail("参数错误");
        }
        String jsonString = JSON.toJSONString(tbAuthCallbackVO);
        log.info("淘宝数据回调参数:" + jsonString);
        log.info("tb数据回调参数:"+ JSON.toJSONString(request.getParameterMap()));

        //参数判断处理及解密
        String result = userAuthTbDubboService.tbDataCallBack(jsonString);
        return result;
    }

}
